/**************************************************************************//**
 * @item     CosyOS-III Kernel
 * @file     sv_task.c
 * @brief    任务服务
 * @details  仅在任务中调用并执行。
 * @author   迟凯峰
 * @version  V2.0.1
 * @date     2025.11.04
 ******************************************************************************/

#include "os_var.h"
#include "os_api.h"
#include "sv_com.h"
#include "sv_task.h"

/**
 @addtogroup 任务服务
 @{
 */

/** 调度解锁（退出嵌套任务临界区）*/
void su_schedule_unlocks(void)
{
	s_schedulelock_counter--;
	if(!s_schedulelock_counter){
		#if (SYSCFG_KERNELLOCKNESTING == __ENABLED__)
		if(!s_sign_schedule.every[1] && !s_kernellock_counter){
		#else
		if(!s_sign_schedule.every[1]){
		#endif
			s_sign_schedule.every[0] = false;
			mPendSV_Set();
			while(!s_sign_schedule.every[1]);
		}
		else{
			s_sign_schedule.every[0] = false;
		}
	}
}

/** 内核解锁（退出嵌套服务层临界区）*/
void su_kernel_unlocks(void)
{
	#if (SYSCFG_KERNELLOCKNESTING == __ENABLED__)
	s_kernellock_counter--;
	if(s_kernellock_counter) return;
	#endif
	if(!s_sign_schedule.total){
		mPendSV_Set();
		mSysIRQ_Enable();
		#if (MCUCFG_ISA == __ARM__)
		OS_NOP(1);
		#endif
		while(!s_sign_schedule.every[1]);
	}
	else{
		mSysIRQ_Enable();
	}
}

/** 内核解锁（退出非嵌套服务层临界区）并触发任务调度 */
void su_kernel_unlock0_psv(void)
{
	s_sign_schedule.every[1] = false;
	mPendSV_Set();
	mSysIRQ_Enable();
	#if (MCUCFG_ISA == __ARM__)
	OS_NOP(1);
	#endif
	while(!s_sign_schedule.every[1]);
}

#if (MCUCFG_ISA != __ARM__)
/** 调度上锁（进入嵌套任务临界区）*/
void su_schedule_locks(void)
{
	s_sign_schedule.every[0] = true;
	s_schedulelock_counter++;
}

/** 内核上锁（进入非嵌套服务层临界区）*/
void su_kernel_lock0(void)
{
	mSysIRQ_Disable();
}

/** 内核上锁（进入嵌套服务层临界区）*/
#if (SYSCFG_KERNELLOCKNESTING == __ENABLED__)
void su_kernel_locks(void)
{
	mSysIRQ_Disable();
	s_kernellock_counter++;
}
#endif

/** 内核解锁（退出嵌套服务层临界区）并返回(s_ecode_t) */
s_ecode_t su_kernel_unlocks_rec(s_ecode_t e)
{
	su_kernel_unlocks();
	return e;
}

/** 内核解锁（退出嵌套服务层临界区）并返回(void *) */
void *su_kernel_unlocks_rvp(void *p)
{
	su_kernel_unlocks();
	return p;
}
#endif


/*
 * 操作任务
 */

/**
 \brief      启动任务
 \param[in]  hhand     任务HAND句柄
 \param[in]  status    任务初始状态
 \return     错误码
 */
s_ecode_t su_startup_task(s_taskhand_tsp hhand, s_u8_t status)
{
	s_task_status0 = status;
	s_task_starter = hhand;
	su_kernel_unlock0_psv();
	return s_startup_ecode;
}

/**
 \brief      恢复指定任务并挂起自身任务
 \param[in]  htask     任务句柄
 \return     错误码
 */
s_ecode_t su_resume_suspend(s_tasknode_tsp htask)
{
	s_ecode_t _ecode = sc_resume_task(htask);
	if(_ecode == OS_ECODE_NOERROR || htask->status == OS_STATUS_READY){
		sa_suspend_task(s_task_current);
		return OS_ECODE_NOERROR;
	}
	else{
		return _ecode;
	}
}

#if (SYSCFG_SAMEPRISCHEDULE == __TIMESHARING__)
/**
 \brief      禅让任务
 \param      无
 \return     无
 */
void su_yield_tasking(void)
{
	su_kernel_locks();
	s_task_current->tc_counter = ~0;
	s_sign_schedule.every[1] = false;
	su_kernel_unlocks();
}
#endif

/**
 \brief      自身任务延时
 \param[in]  tick      滴答周期（延时时间）<br>
             +0：非法<br>
             ~0：无限延时
 \return     无
 */
void su_delay(s_delay_t tick)
{
	s_task_current->timer = tick;
	if(!s_sign_schedule.every[0]){ /* 阻塞延时 */
		if(~tick) sa_insert_timerlist();
		sa_remove_ready(s_task_current);
		s_task_current->status = OS_STATUS_BLOCKED;
		su_kernel_unlock0_psv();
	}
	else{ /* 就绪延时 */
		s_sign_delay = true;
		mSysIRQ_Enable();
		while(s_sign_delay);
	}
}


/*
 * 互斥信号量
 */
#if (SYSCFG_MUTEX == __ENABLED__)
/**
 \brief      获取互斥信号量
 \param[in]  hmut      互斥信号量句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_take_mutex(s_mutex_tsp hmut, s_delay_t tick)
{
	if(!hmut->mutex) goto __RET_TRUE1;
	if(s_task_current == hmut->otask) goto __RET_TRUE2;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hmut->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MUTEX;
	if(s_task_current->pri > hmut->otask->pri){
		#if (SYSCFG_SAMEPRISCHEDULE)
		s_tasknode_tsp link = hmut->otask;
		s_task_current->link = link;
		do{
			sa_set_taskpri(link, s_task_current->pri);
			link = link->link;
		}while(link != OS_NULL);
		#else
		sa_set_taskpri(hmut->otask, s_taskpri_ceiling++);
		#endif
	}
	s_task_current->timer = tick;
	s_task_current->handle = hmut;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hmut = (s_mutex_tsp)s_task_current->handle;
	#endif
	if(!hmut->mutex){
		if(s_task_current->status == OS_STATUS_FLOATING){
			s_task_current->status = OS_STATUS_READY;
			sa_remove_blocklist(s_task_current);
		}
		goto __RET_TRUE1;
	}
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE1:
	if(hmut->htask != OS_NULL){
		sa_float_to_block(hmut->htask);
	}
	hmut->otask = s_task_current;
	hmut->opri = s_task_current->pri;
	
__RET_TRUE2:
	hmut->mutex++;
	mSysIRQ_Enable();
	return true;
}

/**
 \brief      归还互斥信号量
 \param[in]  hmut      互斥信号量句柄
 \return     无
 */
void su_back_mutex(s_mutex_tsp hmut)
{
	if(!hmut->mutex);
	else if(s_task_current == hmut->otask){
		hmut->mutex--;
		if(!hmut->mutex){
			if(s_task_current->pri > hmut->opri){
				sa_set_taskpri(s_task_current, hmut->opri);
				#if (!SYSCFG_SAMEPRISCHEDULE)
				s_taskpri_ceiling--;
				#endif
			}
			if(hmut->htask != OS_NULL){
				sa_block_to_float(hmut->htask);
			}
		}
	}
	su_kernel_unlocks();
}
#endif


/*
 * 二值信号量
 */
#if (SYSCFG_BINARY == __ENABLED__)
/**
 \brief      等待二值信号量
 \param[in]  hbin      二值信号量句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_wait_binary(s_binary_tsp hbin, s_delay_t tick)
{
	if(hbin->binary) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hbin->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_BINARY;
	s_task_current->timer = tick;
	s_task_current->handle = hbin;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hbin = (s_binary_tsp)s_task_current->handle;
	#endif
	if(hbin->binary){
		if(s_task_current->status == OS_STATUS_FLOATING){
			s_task_current->status = OS_STATUS_READY;
			sa_remove_blocklist(s_task_current);
		}
		goto __RET_TRUE;
	}
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	mSysIRQ_Enable();
	return true;
}

/**
 \brief      获取二值信号量
 \param[in]  hbin      二值信号量句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_take_binary(s_binary_tsp hbin, s_delay_t tick)
{
	if(hbin->binary) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hbin->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_BINARY;
	s_task_current->timer = tick;
	s_task_current->handle = hbin;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hbin = (s_binary_tsp)s_task_current->handle;
	#endif
	if(hbin->binary){
		if(s_task_current->status == OS_STATUS_FLOATING){
			s_task_current->status = OS_STATUS_READY;
			sa_remove_blocklist(s_task_current);
		}
		goto __RET_TRUE;
	}
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	if(hbin->htask != OS_NULL){
		sa_float_to_block(hbin->htask);
	}
	hbin->binary = false;
	mSysIRQ_Enable();
	return true;
}
#endif


/*
 * 计数信号量
 */
#if (SYSCFG_SEMAPHORE == __ENABLED__)
/**
 \brief      获取计数信号量
 \param[in]  hsem      计数信号量句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_take_semaph(s_semaph_tsp hsem, s_delay_t tick)
{
	s_semsize_t counter;
	counter = hsem->counter;
	if(counter) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hsem->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_SEMAPHORE;
	s_task_current->timer = tick;
	s_task_current->handle = hsem;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hsem = (s_semaph_tsp)s_task_current->handle;
	#endif
	counter = hsem->counter;
	if(counter){
		if(s_task_current->status == OS_STATUS_FLOATING){
			s_task_current->status = OS_STATUS_READY;
			sa_remove_blocklist(s_task_current);
		}
		goto __RET_TRUE;
	}
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	counter--;
	if(!counter && hsem->htask != OS_NULL){
		sa_float_to_block(hsem->htask);
	}
	hsem->counter = counter;
	mSysIRQ_Enable();
	return true;
}
#endif


/* 
 * 飞信
 */
#if (SYSCFG_FETION == __ENABLED__)
/**
 \brief      退出非嵌套服务层临界区并返回飞信
 \param[in]  htbox     信箱句柄
 \return     飞信
 */
__STATIC_FORCEINLINE m_fetion_t _unlock0_rfet_(s_tionbox_tsp htbox)
{
	m_fetion_t tion = htbox->tion;
	htbox->tion = false;
	mSysIRQ_Enable();
	return tion;
}

/**
 \brief      接收飞信
 \param[in]  htbox     信箱句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     飞信
 \retval     false     失败
 */
m_fetion_t su_recv_fetion(s_tionbox_tsp htbox, s_delay_t tick)
{
	if(htbox->tion) goto __RET_TION;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&htbox->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_FETION;
	s_task_current->timer = tick;
	s_task_current->handle = htbox;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	htbox = (s_tionbox_tsp)s_task_current->handle;
	#endif
	
__RET_TION:
	return _unlock0_rfet_(htbox);
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
}
#endif


/** 退出非嵌套服务层临界区并返回(void *) */
#if (SYSCFG_MAILBOX == __ENABLED__ || SYSCFG_MSGQUEUE == __ENABLED__)
__STATIC_FORCEINLINE void *_unlock0_rvp_(void *p)
{
	mSysIRQ_Enable();
	return p;
}
#endif


/*
 * 邮箱
 */
#if (SYSCFG_MAILBOX == __ENABLED__)
/**
 \brief      接收邮件
 \param[in]  hmbox     邮箱句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     邮件指针
 \retval     NULL      失败
 */
void *su_recv_mail(s_mailbox_tsp hmbox, s_delay_t tick)
{
	if(hmbox->flag) goto __RET_MAIL;
	if(!tick) goto __RET_NULL;
	
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hmbox->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MAIL;
	s_task_current->timer = tick;
	s_task_current->handle = hmbox;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hmbox = (s_mailbox_tsp)s_task_current->handle;
	#endif
	if(hmbox->flag) goto __RET_MAIL;
	
__RET_NULL:
	mSysIRQ_Enable();
	return OS_NULL;
	
__RET_MAIL:
	hmbox->flag = false;
	return _unlock0_rvp_(hmbox->mail);
}
#endif


/*
 * 消息队列
 */
#if (SYSCFG_MSGQUEUE == __ENABLED__)
/**
 \brief      接收消息
 \param[in]  hque      队列句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     消息指针
 \retval     NULL      失败
 */
void *su_recv_msg(s_msgque_tsp hque, s_delay_t tick)
{
	void *msg;
	hque->mutex = false;
	
	if(hque->counter) goto __RECV_MSG;
	if(!tick) goto __RET_NULL;
	
	hque->mutex = true;
	if(~tick) sa_insert_timerlist();
	sa_insert_blocklist(&hque->htask);
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MSG;
	s_task_current->timer = tick;
	s_task_current->handle = hque;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hque = (s_msgque_tsp)s_task_current->handle;
	#endif
	hque->mutex = false;
	if(!hque->counter) goto __RET_NULL;
	
__RECV_MSG:
	if(hque->type == __DYNAMIC__){
		msg = sc_recv_msg_dynque((s_dynque_tsp)hque);
	}
	else{
		msg = sc_recv_msg_staque((s_staque_tsp)hque);
	}
	hque->mutex = true;
	return _unlock0_rvp_(msg);
	
__RET_NULL:
	hque->mutex = true;
	mSysIRQ_Enable();
	return OS_NULL;
}
#endif


/*
 * 事件标志组
 */
#if (SYSCFG_FLAGGROUP == __ENABLED__)
/**
 \brief      查询标志组
 \param[in]  hgrp      标志组句柄
 \param[in]  size      sizeof(group)
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_query_group(volatile void _STATIC_MEM_ *hgrp, s_u8_t size)
{
	switch(size){
	case 1: if(*(s_u8_t  *)hgrp) goto __RET_TRUE; break;
	case 2: if(*(s_u16_t *)hgrp) goto __RET_TRUE; break;
	case 4: if(*(s_u32_t *)hgrp) goto __RET_TRUE; break;
	}
	su_kernel_unlocks();
	return false;
	
__RET_TRUE:
	su_kernel_unlocks();
	return true;
}

/**
 \brief      等待标志组_1
 \param[in]  hgrp      标志组句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_wait_group_1(volatile s_u8_t _STATIC_MEM_ *hgrp, s_delay_t tick)
{
	if(*hgrp) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = 1;
	s_task_current->timer = tick;
	s_task_current->handle = (void *)hgrp;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hgrp = (volatile s_u8_t _STATIC_MEM_ *)s_task_current->handle;
	#endif
	if(*hgrp) goto __RET_TRUE;
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	mSysIRQ_Enable();
	return true;
}

/**
 \brief      等待标志组_2
 \param[in]  hgrp      标志组句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_wait_group_2(volatile s_u16_t _STATIC_MEM_ *hgrp, s_delay_t tick)
{
	if(*hgrp) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = 2;
	s_task_current->timer = tick;
	s_task_current->handle = (void *)hgrp;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hgrp = (volatile s_u16_t _STATIC_MEM_ *)s_task_current->handle;
	#endif
	if(*hgrp) goto __RET_TRUE;
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	mSysIRQ_Enable();
	return true;
}

/**
 \brief      等待标志组_4
 \param[in]  hgrp      标志组句柄
 \param[in]  tick      滴答周期（超时时间）<br>
             +0：立即返回<br>
             ~0：无限等待
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_wait_group_4(volatile s_u32_t _STATIC_MEM_ *hgrp, s_delay_t tick)
{
	if(*hgrp) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	if(~tick) sa_insert_timerlist();
	sa_remove_ready(s_task_current);
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = 4;
	s_task_current->timer = tick;
	s_task_current->handle = (void *)hgrp;
	su_kernel_unlock0_psv();
	#if (SYSCFG_MCUCORE == 8051)
	hgrp = (volatile s_u32_t _STATIC_MEM_ *)s_task_current->handle;
	#endif
	if(*hgrp) goto __RET_TRUE;
	
__RET_FALSE:
	mSysIRQ_Enable();
	return false;
	
__RET_TRUE:
	mSysIRQ_Enable();
	return true;
}
#endif


/*
 * 动态内存
 */
#if (SYSCFG_DYNMEMMGE == __ENABLED__)
/**
 \brief      uxalloc
 \param[in]  p         
 \return     指针
 \retval     NULL      失败
 */
void _MALLOC_MEM_ *su_xalloc(void _MALLOC_MEM_ *p)
{
	su_kernel_unlocks();
	return p;
}

/**
 \brief      初始化线程内存池
 \param[in]  hmem      线程内存句柄
 \param[in]  size      内存池大小
 \return     结果
 \retval     false     失败
 \retval     true      成功
 */
bool su_init_mempool(s_thrmem_tsp hmem, size_t size)
{
	hmem->head = hmem->move = (void _MALLOC_MEM_ *)s_malloc(size);
	if(hmem->head == OS_NULL){
		su_kernel_unlocks();
		return false;
	}
	else{
		hmem->size = size;
		su_kernel_unlocks();
		return true;
	}
}

/**
 \brief      线程内存分配
 \param[in]  hmem      线程内存句柄
 \param[in]  size      内存块大小
 \return     指针
 \retval     NULL      失败
 */
void _MALLOC_MEM_ *su_talloc(s_thrmem_tsp hmem, size_t size)
{
	if(hmem->head == OS_NULL || (size_t)hmem->move - (size_t)hmem->head + size > hmem->size){
		return OS_NULL;
	}
	else{
		void _MALLOC_MEM_ *r = hmem->move;
		hmem->move = (s_u8_t _MALLOC_MEM_ *)hmem->move + size;
		return r;
	}
}
#endif

/** @} */
